package CrowdCountingMVC.CCModel;

import Const.State;
import CrowdCounting.Model.Util;
import CrowdCountingMVC.CCModel.Task.ImageTask.LoadCrowdImageAndNotifyTask;
import CrowdCountingMVC.CCModel.Task.ImageTask.LoadImageAndNotifyTask;
import CrowdCountingMVC.CCModel.Task.ImageTask.LoadWarningImageAndNotifyTask;
import CrowdCountingMVC.CCModel.Task.PythonScriptTask.PythonRunTask;
import CrowdCountingMVC.CCModel.Task.TextTask.LoadTextAndNotifyTask;
import CrowdCountingMVC.CCView.CCObserver.CrowdShowObserver;
import CrowdCountingMVC.CCView.CCObserver.PersonNumShowObserver;
import CrowdCountingMVC.CCView.CCObserver.WarningShowObserver;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;

import static Const.State.*;

public class CrowdCountingModel implements CrowdCountingModelInterface {

    private volatile State showState = CLOSE;

    private List<CrowdShowObserver> crowdCrowdShowObservers;
    private List<WarningShowObserver> warningShowObservers;
    private List<PersonNumShowObserver> personNumShowObservers;
    private File crowdImageFile;
    private File warningImageFile;
    private String personNumText;
    private LoadImageAndNotifyTask loadCrowdImageAndNotifyTask;
    private LoadImageAndNotifyTask loadWarningImageAndNotifyTask;
    private PythonRunTask pythonRunTask;
    private LoadTextAndNotifyTask loadTextAndNotifyTask;

    private static final String END_FLAG_FILE = "python_end_flag.txt";
    private static final String STOP_FLAG_FILE = "python_stop_flag.txt";

    private Properties properties = Util.loadProperties("config.properties");

    public CrowdCountingModel() {
        crowdCrowdShowObservers = new ArrayList<>();
        warningShowObservers = new ArrayList<>();
        personNumShowObservers = new ArrayList<>();
        loadCrowdImageAndNotifyTask = new LoadCrowdImageAndNotifyTask(this, properties.getProperty("crowdImagesPath"));
        loadWarningImageAndNotifyTask = new LoadWarningImageAndNotifyTask(this, properties.getProperty("warningImagesPath"));
        pythonRunTask = new PythonRunTask(true);
        loadTextAndNotifyTask = new LoadTextAndNotifyTask(this, pythonRunTask);
    }

    public State getShowState() {
        return showState;
    }

    public void setShowState(State showState) {
        this.showState = showState;
    }

    public File getCrowdImageFile() {
        return crowdImageFile;
    }

    public void setCrowdImageFile(File crowdImageFile) {
        this.crowdImageFile = crowdImageFile;
    }

    public File getWarningImageFile() {
        return warningImageFile;
    }

    public void setWarningImageFile(File warningImageFile) {
        this.warningImageFile = warningImageFile;
    }

    @Override
    public String getPersonNumText() {
        return personNumText;
    }

    @Override
    public void setPersonNumText(String personNumText) {
        this.personNumText = personNumText;
    }

    public List<CrowdShowObserver> getCrowdCrowdShowObservers() {
        return crowdCrowdShowObservers;
    }

    public List<WarningShowObserver> getWarningShowObservers() {
        return warningShowObservers;
    }

    @Override
    public PythonRunTask getPythonRunTask() {
        return pythonRunTask;
    }

    @Override
    public void start() {
        if (new File(END_FLAG_FILE).exists() && !new File(END_FLAG_FILE).delete()) {
            Util.logger(Level.WARNING, "Failed to remove the END FLAG file");
            return;
        }
        if (new File(STOP_FLAG_FILE).exists() && !new File(STOP_FLAG_FILE).delete()) {
            Util.logger(Level.WARNING, "Failed to remove the STOP FLAG file");
            return;
        }
        switch (getShowState()) {
            case CLOSE:
                startForFirst();//初始启动
                break;
            case STOP:
                setShowState(START);//暂停后启动
                break;
        }
    }

    private void startForFirst() {
        setShowState(START);
        while (pythonRunTask != null && pythonRunTask.isAlive()) {
            Util.sleepTime(1000);
            pythonRunTask.endPythonScript();
        }

        new Thread(pythonRunTask, "pythonScriptTask").start();
        Util.sleepTime(2000);

        new Thread(loadCrowdImageAndNotifyTask, "loadCrowdImageAndNotifyTask").start();
        new Thread(loadWarningImageAndNotifyTask, "loadWarningImageAndNotifyTask").start();
        new Thread(loadTextAndNotifyTask, "loadTextAndNotifyTask").start();
    }

    @Override
    public void stop() {
        if (getShowState() == CLOSE) return;
        setShowState(STOP);
        Util.logger(Level.INFO, "Press to stop");
        if (!Util.createFile(STOP_FLAG_FILE)) {
            System.out.println("python脚本暂停标志文件创建失败");
        }
    }

    @Override
    public void end() {
        if (getShowState() == CLOSE) return;
        setShowState(CLOSE);
        Util.logger(Level.INFO, "Press to close");
        clearPythonScriptInput();
        if (!Util.fileExistenceCheck(END_FLAG_FILE) &&!Util.createFile(END_FLAG_FILE)) {
            Util.logger(Level.WARNING, "Python脚本结束标志文件创建失败");
        }
        pythonRunTask.endPythonScript();
    }

    private void clearPythonScriptInput() {
        ArrayList<String> cmdList = pythonRunTask.getCmdList();
        while (cmdList.size() > 6) {
            cmdList.remove(cmdList.size() - 1);
        }
    }

    @Override
    public void inputParam(String param) {
        pythonRunTask.addInputValueToCmd(param);
    }

    @Override
    public void registerCrowdShowObserver(CrowdShowObserver observer) {
        crowdCrowdShowObservers.add(observer);
    }

    @Override
    public void registerWarningShowObserver(WarningShowObserver observer) {
        warningShowObservers.add(observer);
    }

    @Override
    public void registerPersonNumShowObserver(PersonNumShowObserver observer) {
        personNumShowObservers.add(observer);
    }

    public void notifyCrowdShowObserver() {
        Iterator<CrowdShowObserver> iterator = getCrowdCrowdShowObservers().iterator();
        while (iterator.hasNext()) {
            iterator.next().updateCrowdShow();
        }
    }

    public void notifyWarningShowObserver() {
        Iterator<WarningShowObserver> iterator = getWarningShowObservers().iterator();
        while (iterator.hasNext()) {
            iterator.next().updateWarningShow();
        }
    }

    public void notifyPersonNumShowObserver() {
        for (PersonNumShowObserver observer : personNumShowObservers) {
            observer.updatePersonNumShow();
        }
    }
}
